import DeviceInfo from 'react-native-device-info';
import * as Keychain from 'react-native-keychain';
import Toast from 'react-native-toast-message';

import {
  ACCESS_TOKEN,
  ACCESS_TOKEN_EXPIRE_TIME,
  APP_NAME,
  APP_NAME_FOR_AGREEMENT_URL,
  DEVICE_ID,
  REFRESH_TOKEN,
  REFRESH_TOKEN_EXPIRE_TIME,
  USER_ID,
} from '../constants';
import { userAPI } from './userAPI.ts';
import { getStorageItem, getStorageNumberItem, setStorageItem } from '../utils/storage';

// 一些用户协议和隐私政策的链接
// 会员服务URL,订阅协议URL
export const VipAgreementUrl = `https://res.turingsynergy.com/draft/${APP_NAME_FOR_AGREEMENT_URL}/Terms-and-Conditions.html`; // 会员服务协议
// 用户隐私协议
export const PrivacyAgreementUrl = `https://res.turingsynergy.com/draft/${APP_NAME_FOR_AGREEMENT_URL}/Privacy-Policy.html`; // 用户隐私协议
// 订阅协议
export const SubscriptionAgreementUrl = `https://res.turingsynergy.com/draft/${APP_NAME_FOR_AGREEMENT_URL}/Subscription.html`;

/**
 * 获取设备UUID 用于唯一标识设备
 */
export const getUUID = async () => {
  // 注意，因为在苹果手机上，如果卸载了软件再重新安装，设备ID会变化
  // 这里使用react-native-keychain去向苹果手机的钥匙串存储用户的唯一设备ID

  // 用户名，存储在钥匙串使用
  const username = `_ts_app_${APP_NAME}_deviceUsername`;
  // 密码，这里设为当前设备ID
  let password = '';
  try {
    password = await DeviceInfo.getUniqueId();
  } catch (error) {
    console.error(error);
    Toast.show({
      type: 'tips',
      text1: 'Failed to obtain device information for the first time',
      props: {
        _type: 'error',
      },
    });

    throw new Error('Failed to obtain device information for the first time');
  }
  console.log('current uuid====', password);

  // 如果苹果钥匙串没有存储设备ID，则向苹果钥匙串存储设备ID
  try {
    const currentCredentials = await Keychain.getGenericPassword();
    // 如果钥匙串中没有存储设备ID，则向钥匙串中存储设备ID
    if (!currentCredentials || currentCredentials.username !== username) {
      try {
        // 钥匙串存储设备ID
        const res = await Keychain.setGenericPassword(username, password);

        console.log('keychain set res====', res);
        // 并且在应用上也存储设备ID
        setStorageItem(DEVICE_ID, password);
        console.log('keychain set uuid====', password);

        // 返回设备ID
        return password;
      } catch (error) {
        console.log('Keychain setGenericPassword failed!', error);

        Toast.show({
          type: 'tips',
          text1: 'Keychain storage device ID failed',
          props: {
            _type: 'error',
          },
        });
        // 这里即使往钥匙串里面存储不了设备ID，就手动存储
        setStorageItem(DEVICE_ID, password);
        // 返回设备ID
        return password;
        // throw new Error('Keychain storage device ID failed');
      }
    }
    // 如果钥匙串中已经存储了设备ID，则获取钥匙串上的设备ID,并且在应用上也存储设备ID
    const deviceIdOnKeychain = currentCredentials.password;
    setStorageItem(DEVICE_ID, deviceIdOnKeychain);
    console.log('keychain get uuid====', deviceIdOnKeychain);

    // 返回设备ID
    return deviceIdOnKeychain;
  } catch (error) {
    console.error(error);
    console.log("Keychain couldn't be accessed!", error);
    // 这里即使往钥匙串里面存储不了设备ID，就手动存储
    setStorageItem(DEVICE_ID, password);
    // 返回设备ID
    return password;
  }
};

/**
 * 本地存储用户loginToken信息
 * @param res
 */
export const setUserLoginToken = (res: User.TokenInfo) => {
  // 设置用户ID
  setStorageItem(USER_ID, res.userId);
  // 设置token
  setStorageItem(ACCESS_TOKEN, res.accessToken);
  // accessToken有效时长.时间节点
  setStorageItem(ACCESS_TOKEN_EXPIRE_TIME, res.expiresIn ? Date.now() + (res.expiresIn || 0) * 1000 : 0);
  // refresh_token
  setStorageItem(REFRESH_TOKEN, res.refreshToken);
  // refreshToken有效时长
  setStorageItem(REFRESH_TOKEN_EXPIRE_TIME, res.refreshExpiresIn ? Date.now() + (res.refreshExpiresIn || 0) * 1000 : 0);
};

/**
 * 请求获取用户ID 和token和freshToken，并设置到本地存储
 */
export const requestToken = async () => {
  const deviceId = await getUUID();

  // 1.判断用户的accessToken是否过期
  const accessTokenExpireTime = getStorageNumberItem(ACCESS_TOKEN_EXPIRE_TIME);
  const userId = getStorageItem(USER_ID);

  // 如果accessToken未过期，则直接跳过,并跳转到创作页
  if (userId && accessTokenExpireTime && accessTokenExpireTime > Date.now()) {
    return {
      userId: userId,
    };
  }
  // 2.如果accessToken已过期，但是refreshToken未过期，则使用refreshToken获取新的accessToken
  const refreshToken = getStorageItem(REFRESH_TOKEN);

  const refreshTokenExpireTime = getStorageNumberItem(REFRESH_TOKEN_EXPIRE_TIME);

  try {
    if (refreshToken && refreshTokenExpireTime && refreshTokenExpireTime > Date.now()) {
      // 调用刷新token接口
      const res = await userAPI.auth_login({
        grantType: 'refreshToken',
        appName: APP_NAME,
        refreshToken: refreshToken,
        userType: 'app_user',
      });

      // 本地存储用户信息
      setUserLoginToken(res.data);

      // 返回用户信息,不做页面跳转
      return res.data;
    } else {
      // 3.如果refreshToken已过期，则重新发起设备号登录请求
      const res = await userAPI.device_login({
        appName: APP_NAME,
        deviceId: deviceId,
      });
      // 本地存储用户信息
      setUserLoginToken(res.data);
      return res.data;
    }
  } catch (error) {
    console.error(error);
  }
};
